import * as pdfjsLib from "pdfjs-dist/legacy/build/pdf";
import { fabric } from "fabric";

import jsPDF from "jspdf";
import { generateUUID, getNewDataFn } from "./utils";
import Arrow from "./utils/arrow.fabric";
// 设置 PDF.js 的 Worker 脚本路径
pdfjsLib.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.js";

export const PDFAnnotate = function (container_id, url, options = {}) {
  this.number_of_pages = 0;
  this.pages_rendered = 0;
  this.active_tool = 0; // 1 - Free hand, 2 - Text, 3 - Arrow, 4 - Rectangle
  this.fabricObjects = [];
  this.fabricObjectsData = [];
  this.color = "#212121";
  this.borderColor = "#000000";
  this.borderSize = 1;
  this.font_size = 16;
  this.active_canvas = 0;
  this.container_id = container_id;
  this.url = url;
  this.pageImageCompression = options.pageImageCompression
    ? options.pageImageCompression.toUpperCase()
    : "NONE";
  this.textBoxText = "请双击后注释";
  this.format;
  this.orientation;
  let inst = this;

  let loadingTask = pdfjsLib.getDocument(this.url);
  loadingTask.promise.then(
    function (pdf) {
      const scale = options.scale || 1.3; // 使用逻辑或运算符简化赋值
      inst.number_of_pages = pdf.numPages;

      function renderPage(page, index) {
        const originalViewport = page.getViewport({ scale: 1 });
        if (!inst.format || !inst.orientation) {
          inst.format = [originalViewport.width, originalViewport.height];
          inst.orientation =
            originalViewport.width > originalViewport.height ? "landscape" : "portrait";
        }

        const viewport = page.getViewport({ scale: scale });
        const canvas = document.createElement("canvas");
        canvas.className = "pdf-canvas";
        canvas.height = viewport.height;
        canvas.width = viewport.width;
        canvas.id = `page-${index + 1}-canvas`; // 直接设置 id，无需后续遍历
        document.getElementById(inst.container_id).appendChild(canvas);

        const context = canvas.getContext("2d");
        const renderContext = { canvasContext: context, viewport: viewport };
        const renderTask = page.render(renderContext);

        renderTask.promise.then(() => {
          inst.pages_rendered++;
          if (inst.pages_rendered === inst.number_of_pages) inst.initFabric();
        });
      }

      // 使用 Promise.all 来处理页面渲染，确保所有页面都渲染完成后再执行后续操作
      Promise.all(
        Array.from({ length: pdf.numPages }, (_, i) => i + 1).map((pageNum) => {
          return pdf.getPage(pageNum).then((page) => renderPage(page, pageNum - 1));
        })
      );
    },
    function (reason) {
      console.error(reason);
    }
  );

  this.initFabric = function () {
    let inst = this;
    let canvases = document.querySelectorAll("#" + inst.container_id + " canvas");
    canvases.forEach(function (el, index) {
      let background = el.toDataURL("image/png");
      let fabricObj = new fabric.Canvas(el.id, {
        freeDrawingBrush: {
          width: 1,
          color: inst.color,
        },
      });

      fabricObj.on("before:path:created", function (e) {
        const path = e.path;
        path.customData = {
          id: generateUUID(),
        };
      });

      inst.fabricObjects.push(fabricObj);
      if (typeof options.onPageUpdated == "function") {
        fabricObj.on("object:added", function () {
          let oldValue = Object.assign({}, inst.fabricObjectsData[index]);
          inst.fabricObjectsData[index] = fabricObj.toJSON();
          const newValue = getNewDataFn(oldValue, inst.fabricObjectsData[index]);
          options.onPageUpdated(index + 1, oldValue, newValue[0]);
        });
      }
      fabricObj.setBackgroundImage(background, fabricObj.renderAll.bind(fabricObj));
      fabricObj.upperCanvasEl.addEventListener("click", function (event) {
        inst.active_canvas = index;
        inst.fabricClickHandler(event, fabricObj);
      });
      fabricObj.on("after:render", function () {
        inst.fabricObjectsData[index] = fabricObj.toJSON();
        fabricObj.off("after:render");
      });

      fabricObj.on("mouse:down", function (event) {
        console.log(event.target);
        options.mousedownFn(event.target || null, inst.fabricObjects, index);
      });

      if (index === canvases.length - 1 && typeof options.ready === "function") {
        options.ready();
      }
    });
    options.initFinish();
  };

  this.fabricClickHandler = function (event, fabricObj) {
    let inst = this;
    let toolObj;

    if (inst.active_tool == 2) {
      toolObj = new fabric.IText(inst.textBoxText, {
        left: event.clientX - fabricObj.upperCanvasEl.getBoundingClientRect().left,
        top: event.clientY - fabricObj.upperCanvasEl.getBoundingClientRect().top,
        fill: inst.color,
        fontSize: inst.font_size,
        selectable: true,
        splitByGrapheme: true, // 自动换行
        customData: {
          id: generateUUID(),
        },
      });
    } else if (inst.active_tool == 4) {
      toolObj = new fabric.Rect({
        left: event.clientX - fabricObj.upperCanvasEl.getBoundingClientRect().left,
        top: event.clientY - fabricObj.upperCanvasEl.getBoundingClientRect().top,
        width: 100,
        height: 100,
        fill: inst.color,
        stroke: inst.borderColor,
        strokeSize: inst.borderSize,
        customData: {
          id: generateUUID(),
        },
      });
    }
    if (toolObj) {
      fabricObj.add(toolObj);
    }
  };
};

PDFAnnotate.prototype.enableSelector = function () {
  let inst = this;
  inst.active_tool = 0;
  if (inst.fabricObjects.length > 0) {
    inst.fabricObjects.forEach(function (fabricObj, index) {
      fabricObj.isDrawingMode = false;
    });
  }
};

PDFAnnotate.prototype.enablePencil = function () {
  let inst = this;
  inst.active_tool = 1;
  if (inst.fabricObjects.length > 0) {
    inst.fabricObjects.forEach(function (fabricObj, index) {
      fabricObj.isDrawingMode = true;
    });
  }
};

PDFAnnotate.prototype.enableAddText = function (text) {
  let inst = this;
  inst.active_tool = 2;
  if (typeof text === "string") {
    inst.textBoxText = text;
  }
  if (inst.fabricObjects.length > 0) {
    inst.fabricObjects.forEach(function (fabricObj) {
      fabricObj.isDrawingMode = false;
    });
  }
};

PDFAnnotate.prototype.enableRectangle = function () {
  let inst = this;
  let fabricObj = inst.fabricObjects[inst.active_canvas];
  inst.active_tool = 4;
  if (inst.fabricObjects.length > 0) {
    inst.fabricObjects.forEach((obj) => (obj.isDrawingMode = false));
  }
};

PDFAnnotate.prototype.enableAddArrow = function (onDrawnCallback = null) {
  let inst = this;
  inst.active_tool = 3;
  if (inst.fabricObjects.length > 0) {
    const arrowList = [];
    inst.fabricObjects.forEach(function (fabricObj) {
      fabricObj.isDrawingMode = false;
      const arrow = new Arrow(fabricObj, inst.color, function () {
        inst.active_tool = 0;
        // 取消所有绑定的画布事件
        arrowList.forEach((item) => item.unBindEventes());
        if (typeof onDrawnCallback === "function") {
          onDrawnCallback();
        }
      });
      arrowList.push(arrow);
    });
  }
};

PDFAnnotate.prototype.addImageToCanvas = function () {
  let inst = this;
  let fabricObj = inst.fabricObjects[inst.active_canvas];

  if (fabricObj) {
    let inputElement = document.createElement("input");
    inputElement.type = "file";
    inputElement.accept = ".jpg,.jpeg,.png,.PNG,.JPG,.JPEG";
    inputElement.onchange = function () {
      let reader = new FileReader();
      reader.addEventListener(
        "load",
        function () {
          inputElement.remove();
          let image = new Image();
          image.onload = function () {
            const fabricImage = new fabric.Image(image);
            fabricImage.set({
              customData: {
                id: generateUUID(),
              },
            });
            fabricObj.add(fabricImage);
          };
          image.src = this.result;
        },
        false
      );
      reader.readAsDataURL(inputElement.files[0]);
    };
    document.getElementsByTagName("body")[0].appendChild(inputElement);
    inputElement.click();
  }
};

PDFAnnotate.prototype.deleteSelectedObject = function () {
  let inst = this;
  let activeObject = inst.fabricObjects[inst.active_canvas].getActiveObject();
  if (activeObject) {
    if (confirm("Are you sure ?")) {
      inst.fabricObjects[inst.active_canvas].remove(activeObject);
    }
  }
};

PDFAnnotate.prototype.savePdf = function (fileName) {
  let inst = this;
  let format = inst.format || "a4";
  let orientation = inst.orientation || "portrait";
  if (!inst.fabricObjects.length) return;
  let doc = new jsPDF({ format, orientation });
  if (typeof fileName === "undefined") {
    fileName = `${new Date().getTime()}.pdf`;
  }

  inst.fabricObjects.forEach(function (fabricObj, index) {
    if (index != 0) {
      doc.addPage(format, orientation);
      doc.setPage(index + 1);
    }
    doc.addImage(
      fabricObj.toDataURL({
        format: "png",
      }),
      inst.pageImageCompression == "NONE" ? "PNG" : "JPEG",
      0,
      0,
      doc.internal.pageSize.getWidth(),
      doc.internal.pageSize.getHeight(),
      `page-${index + 1}`,
      ["FAST", "MEDIUM", "SLOW"].indexOf(inst.pageImageCompression) >= 0
        ? inst.pageImageCompression
        : undefined
    );
    if (index === inst.fabricObjects.length - 1) {
      doc.save(fileName);
    }
  });
};

PDFAnnotate.prototype.setBrushSize = function (size) {
  let inst = this;
  inst.fabricObjects.forEach(function (fabricObj) {
    fabricObj.freeDrawingBrush.width = parseInt(size, 10) || 1;
  });
};

PDFAnnotate.prototype.setColor = function (color) {
  let inst = this;
  inst.color = color;
  inst.fabricObjects.forEach(function (fabricObj) {
    fabricObj.freeDrawingBrush.color = color;
  });
};

PDFAnnotate.prototype.setBorderColor = function (color) {
  let inst = this;
  inst.borderColor = color;
};

PDFAnnotate.prototype.setFontSize = function (size) {
  this.font_size = size;
};

PDFAnnotate.prototype.setBorderSize = function (size) {
  this.borderSize = size;
};

PDFAnnotate.prototype.clearActivePage = function () {
  let inst = this;
  let fabricObj = inst.fabricObjects[inst.active_canvas];
  let bg = fabricObj.backgroundImage;
  if (confirm("Are you sure?")) {
    fabricObj.clear();
    fabricObj.setBackgroundImage(bg, fabricObj.renderAll.bind(fabricObj));
  }
};

PDFAnnotate.prototype.serializePdf = function (callback) {
  let inst = this;
  let pageAnnotations = [];
  inst.fabricObjects.forEach(function (fabricObject) {
    fabricObject.clone(function (fabricObjectCopy) {
      fabricObjectCopy.setBackgroundImage(null);
      fabricObjectCopy.setBackgroundColor("");
      pageAnnotations.push(fabricObjectCopy);
      if (pageAnnotations.length === inst.fabricObjects.length) {
        let data = {
          page_setup: {
            format: inst.format,
            orientation: inst.orientation,
          },
          pages: pageAnnotations,
        };
        callback(JSON.stringify(data));
      }
    });
  });
};

PDFAnnotate.prototype.loadFromJSON = function (jsonData) {
  let inst = this;
  let { page_setup, pages } = jsonData;
  if (typeof pages === "undefined") {
    pages = jsonData;
  }
  if (
    typeof page_setup === "object" &&
    typeof page_setup.format === "string" &&
    typeof page_setup.orientation === "string"
  ) {
    inst.format = page_setup.format;
    inst.orientation = page_setup.orientation;
  }
  inst.fabricObjects.forEach(function (fabricObj, index) {
    if (pages.length > index) {
      fabricObj.loadFromJSON(pages[index], function () {
        inst.fabricObjectsData[index] = fabricObj.toJSON();
      });
    }
  });
};

PDFAnnotate.prototype.setDefaultTextForTextBox = function (text) {
  let inst = this;
  if (typeof text === "string") {
    inst.textBoxText = text;
  }
};

PDFAnnotate.prototype.selectElement = function (event) {
  console.log(event);
  let inst = this;
  const canvas = inst.fabricObjects[inst.active_canvas];
  let eleSelect = canvas.getObjects()[0];
  canvas.setActiveObject(eleSelect, "mouse:down");
  canvas.renderAll();
};

fabric.Object.prototype.toObject = (function (toObject) {
  return function () {
    return fabric.util.object.extend(toObject.call(this), {
      customData: this.customData,
      text: this.text,
      styles: this.styles,
    });
  };
})(fabric.Object.prototype.toObject);
